Skip to main content

05 Scheme

这篇笔记包含第十一、十二周的内容和第十三章的第一个lecture,只关注scheme的语法(基本不涉及calculator和interpreter部分)。

scheme基础

scheme是一种函数式编程语言,用函数来构造程序。可以理解为,scheme的内容基本遵循 (f a b c ...) 的格式,其中 f 为函数,后面为参数,用空格分隔。即使是最简单的运算都使用这种表达形式,例如 (+ 1 1)

控制流与函数

scheme中的分支为

(if condition
A
B)

condition 为真时,表达式的值为 A ,否则为 BB 可以省略(相当于没有 elseif )。

scheme中没有循环表达式,循环通过递归来实现。

(define (sum-first-n n) 
(define (f k total)
(if (> k n)
total
(f (+ k 1) (+ total k))))
(f 1 0))

函数为

(define (name arg1 arg2 ...)
return-value)

例如

(define (fib n)
(if (or (= n 0) (= n 1))
n
(+ (fib (- n 2)) (fib (- n 1)))))

lambda 表达式

lambda表达式格式为

(lambda (<formal-parameters>) <body>)

例如

(lambda (x y z) (+ x y (square z)))

let 表达式

表达式格式

(let (<let-expression>) <body>)

其中 let-expression 为数个 (name value)

(define c (let ((a 3)  
(b (+ 2 2)))
(sqrt (+ (* a a) (* b b)))))

注意, let 定义的量的作用域范围只在括号内。

cond 和 begin

cond 可以达到类似 elif 的效果。

(cond <cond-expression>)

cond-expression 为数个 (condition value)condition 可以为 else

 if x > 10: 
print('big')
elif x > 5:
print('medium')
else:
print('small')
(cond ((> x 10) (print 'big))
((> x 5) (print 'medium)
(else 'small)))

begin 可以在一个分支里执行多条语句。

(begin <begin-expression>)

begin-expression 为数条语句。

if x > 10:
print('big')
print('guy')
else:
print('small')
print('fry')
(if (> x 10)
(begin
(print 'big)
(print 'guy))
(begin
(print 'small)
(print 'fry)))

scheme list

基本操作

scheme中的列表和python中类似。列表中的每个元素分为两个部分:它的值和连接的下一个列表。

cons 有两个参数,分别为值和列表,用于创建列表。 nil 为空列表。

(由于设定上是在终端中,这部分代码没有高亮)

> (cons 1 (cons 2 nil))
(1 2)
> (cons 1 (cons 2 (cons 3 (cons 4 nil))))
(1 2 3 4)

carcdr 分别用于获取列表的第一个(值)和第二个(下一个列表)元素。

> (define x (cons 1 (cons 2 nil)))
> x
(1 2)
> (car x)
1
> (cdr x)
(2)

其它

(list <arguments>) 将所有参数作为元素组成一个链表。

> (list 1 2 3 4)
(1 2 3 4)

(append <argumens>) 的所有参数均为链表,将其连接在一起产生一个新链表。注意 list 的参数为值, append 的参数为链表。

> (define x (cons 1 (cons 2 nil)))
> (define y (cons 3 (cons 4 nil)))
> (append x y)
(1 2 3 4)

引用

scheme中的引用分为quote和quasiquote。

quote的格式为 (quota obj)'obj ,会阻止表达式求值,直接返回字面内容。

quasiquote的格式为 (quasiquote obj) `obj ,也会直接返回字面内容。可以用 , 来unquote,将某些部分求值后再插入。嵌套时,只对同一层(最外层)中的解引用部分求值。

> (define b 1)
> `(a `(,b))
(a (b))

宏(macro)指“在程序求值之前对代码执行的操作”(例如C中的 #define N 10000`` ),会对代码进行某种“替换”。

scheme中可以用 define-macro 语句来定义宏。

(define-macro (twice expr)
(list 'begin expr expr))

这里的twice 就是一个宏。

> (twice (print 2))
2
2

在执行 (twice (print 2)) 时,这个语句被替换为了 (begin (print 2) (print 2)) ,然后执行替换后的代码。